import json
import time
import hmac
import logging
import hashlib
import base64
from urllib.parse import urlparse, urlencode
import websocket
from channels.db import database_sync_to_async
from django.conf import settings
import asyncio
from Interview.models import Interview
from Resume.models import Resume

XF_WS_URL = settings.XF_SPARK_ULTRA_API_HOST
logger = logging.getLogger(__name__)


class WsParam:
    def __init__(self):
        o = urlparse(XF_WS_URL)
        self.host = o.netloc
        self.path = o.path

    def create_url(self):
        date = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
        sign_str = f"host: {self.host}\ndate: {date}\nGET {self.path} HTTP/1.1"
        sig = base64.b64encode(
            hmac.new(settings.XF_API_SECRET.encode(), sign_str.encode(), hashlib.sha256).digest()
        ).decode()
        auth_str = (
            f'api_key="{settings.XF_API_KEY}", algorithm="hmac-sha256", '
            f'headers="host date request-line", signature="{sig}"'
        )
        auth_b64 = base64.b64encode(auth_str.encode()).decode()
        params = {"authorization": auth_b64, "date": date, "host": self.host}
        return XF_WS_URL + "?" + urlencode(params)


async def _generate_ai_question(interview_id: int, last_answer: str):
    # 获取面试和简历结构化数据
    interview = await database_sync_to_async(Interview.objects.get)(pk=interview_id)
    resume = await database_sync_to_async(
        lambda uid: Resume.objects.filter(user_id=uid).order_by('-upload_time').first()
    )(interview.user_id)
    parsed = resume.parsed_data if resume else {}

    # 构建提示词
    prompt = (
        f"候选人简历信息：{json.dumps(parsed, ensure_ascii=False)}。"
        f"上一条回答：{last_answer}。"
        "你是一个资深的面试官，请基于候选人的简历和刚才的回答，给出一个深挖性追问，用一句话。"
    )
    result = {'content': '', 'error': None}

    def on_message(ws, message):
        data = json.loads(message)
        if data.get('header', {}).get('code') != 0:
            result['error'] = data
            ws.close()
            return
        # 累积内容
        chunk = (
            data.get('payload', {})
            .get('choices', {})
            .get('text', [{}])[0]
            .get('content', '')
        )
        result['content'] += chunk
        if data.get('header', {}).get('status') == 2:
            ws.close()

    def on_open(ws):
        payload = {
            'header': {
                'app_id': settings.XF_APPID,
                'uid': 'user_report'
            },
            'parameter': {
                'chat': {
                    'domain': '4.0Ultra',
                    'temperature': 0.7,
                    'max_tokens': 8192,
                    'top_k': 4,
                    'show_ref_label': True
                }
            },
            'payload': {'message': {'text': [{'role': 'user', 'content': prompt}]}}
        }
        ws.send(json.dumps(payload))

    def on_error(ws, error, *args):
        # 捕获并记录错误
        result['error'] = error
        try:
            ws.close()
        except Exception:
            pass

    def on_close(ws, close_status_code, close_msg):
        # WebSocket 关闭回调
        pass

    ws = websocket.WebSocketApp(
        WsParam().create_url(),
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )

    # 在 executor 中运行，使用 lambda 传递关键字参数
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(
        None,
        lambda: ws.run_forever(ping_interval=30)
    )

    if result['error']:
        raise RuntimeError(f"讯飞调用失败：{result['error']}")

    question = result['content'].strip()
    qtype = 'technical' if '技术' in question else 'behavioral'
    return question, qtype, {'resume_parsed': parsed}


async def analyze_answer_text(interview_id: int, question: str, answer_text: str) -> dict:
    """
    使用 AI 对一次回答进行深度分析，包含简历信息、题目和回答。
    返回 JSON 格式的分析指标。
    """
    # 1) 异步安全地查询 Interview
    interview = await database_sync_to_async(Interview.objects.get)(pk=interview_id)
    # 2) 异步安全地查询最新 Resume
    resume = await database_sync_to_async(
        lambda uid: Resume.objects.filter(user_id=uid).order_by('-upload_time').first()
    )(interview.user_id)
    parsed = resume.parsed_data if resume else {}

    # 3) 构建提示词并调用 WebSocket AI
    prompt = (
        f"候选人简历信息：{json.dumps(parsed, ensure_ascii=False)}。\n"
        f"面试问题：{question}\n"
        f"回答内容：{answer_text}\n"
        "请基于以上信息，对回答给出以下维度评分：\n"
        "- clarity（清晰度，0-10）\n"
        "- structure（逻辑结构，0-10）\n"
        "- coverage（要点覆盖度，0-10）\n"
        "并给出改进建议列表，"
        "最后输出纯 JSON（不要代码块、不要多余文本），格式如：\n"
        "{\"clarity\":8.5, \"structure\":7.0, \"coverage\":9.0, \"suggestions\":[\"…\"]}"
    )
    result = {'content': '', 'error': None}

    def on_message(ws, message):
        data = json.loads(message)
        if data.get('header', {}).get('code') != 0:
            result['error'] = data
            ws.close()
            return
        chunk = (
            data.get('payload', {})
            .get('choices', {})
            .get('text', [{}])[0]
            .get('content', '')
        )
        result['content'] += chunk
        if data.get('header', {}).get('status') == 2:
            ws.close()

    def on_open(ws):
        payload = {
            'header': {
                'app_id': settings.XF_APPID,
                'uid': 'user_report'
            },
            'parameter': {
                'chat': {
                    'domain': '4.0Ultra',
                    'temperature': 0.7,
                    'max_tokens': 8192,
                    'top_k': 4,
                    'show_ref_label': True
                }
            },
            'payload': {'message': {'text': [{'role': 'user', 'content': prompt}]}}
        }
        ws.send(json.dumps(payload))

    ws = websocket.WebSocketApp(
        WsParam().create_url(),
        on_open=on_open,
        on_message=on_message,
        on_error=lambda ws, e: result.update(error=str(e)),
        on_close=lambda ws, code, msg: None
    )

    # 同步执行 WebSocket
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, lambda: ws.run_forever(ping_interval=30))

    if result['error']:
        raise RuntimeError(f"回答分析失败：{result['error']}")

    #  处理返回结果
    if result['error']:
        logger.error("AI 分析接口报错：%s", result['error'])
        return {
            "clarity": 0,
            "structure": 0,
            "coverage": 0,
            "suggestions": ["AI 调用失败，未获取分析结果。"]
        }

    raw = result['content'].strip()
    # 剥离可能存在的 Markdown 代码块
    if raw.startswith("```") and raw.endswith("```"):
        # 去掉第一行 ```json 和最后一行 ```
        lines = raw.splitlines()
        raw = "\n".join(lines[1:-1]).strip()

    # 如果依然不是以 "{" 开头，视作异常
    if not raw or not raw.startswith("{"):
        logger.error("analyze_answer_text 得到非 JSON 内容，无法解析，原始内容：%r", raw)
        return {
            "clarity": 0,
            "structure": 0,
            "coverage": 0,
            "suggestions": ["AI 返回格式不正确，未能生成有效分析。"]
        }

    # JSON 解析
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        logger.exception("解析 AI 返回 JSON 失败")
        return {
            "clarity": 0,
            "structure": 0,
            "coverage": 0,
            "suggestions": ["AI 返回的 JSON 无效，解析失败。"]
        }
